/**
 * \file value.h
 * \brief RValue, a generic container for any RScript datatype.
 **/

#ifndef R_VALUE_H
#define R_VALUE_H

#include "standard.h"

/* Possible RValues */
struct RMapT;
typedef struct RMapT RMap;
struct RArrayT;
typedef struct RArrayT RArray;

struct RValueT {
  union {
    uintptr_t type;
  };
  union {
    int32_t val_int;
    RMap* val_map;
    void* val_p;
    struct RValueT * val_tuple;
    RArray* val_array;
  };
};
typedef struct RValueT RValue;


/*** Types of RValues ***/

/**
 * \brief This RValue is special. This isn't an actual type, and is only
 * used internally by complex data types (such as Map).
 **/
#define R_VALUE_SPEC 0

/**
 * \brief This RValue is a raw signed integer (direct value)
 **/
#define R_VALUE_INT 1

/**
 * \brief This RValue is a map (reference).
 **/
#define R_VALUE_MAP 2

/**
 * \brief This RValue is an opaque void* (reference).
 **/
#define R_VALUE_POINTER 3

/**
 * \brief This RValue is a an array (reference).
 **/
#define R_VALUE_ARRAY 4

/**
 * \brief This RValue is a true (direct value).
 **/
#define R_VALUE_TRUE 5

/**
 * \brief This RValue is a false (direct value).
 **/
#define R_VALUE_FALSE 6

/**
 * \brief This RValue is a tuple. A tuple can be have at most 64 elements.
 * Size of the tuple is given by adding size to R_VALUE_TUPLE. A tuple is
 * implemented as a reference, but acts like a direct value in terms of
 * calculating hashes and equality.
 **/
#define R_VALUE_TUPLE 63


/*** Type checkers ***/

#define r_value_is_spec(val)    ((val).type == R_VALUE_SPEC)
#define r_value_is_int(val)     ((val).type == R_VALUE_INT)
#define r_value_is_map(val)     ((val).type == R_VALUE_MAP)
#define r_value_is_pointer(val) ((val).type == R_VALUE_POINTER)
#define r_value_is_array(val)   ((val).type == R_VALUE_ARRAY)
#define r_value_is_bool(val)    (((val).type == R_VALUE_TRUE) or \
                                  ((val).type == R_VALUE_FALSE))
#define r_value_is_true(val)    ((val).type == R_VALUE_TRUE)
#define r_value_is_false(val)   ((val).type == R_VALUE_FALSE)
#define r_value_is_tuple(val)   (((val).type > R_VALUE_TUPLE) and \
                                  ((val).type <= (R_VALUE_TUPLE + 64)))


/*** Constructors ***/

#define r_value_from_int32(n)   ((RValue) {{.type = R_VALUE_INT}, \
                                               {.val_int = n} })

#define r_value_from_pointer(p) ((RValue) {{.type = R_VALUE_POINTER}, \
                                               {.val_p = p} })

#define r_value_true()          ((RValue) {{.type = R_VALUE_TRUE}})

#define r_value_false()         ((RValue) {{.type = R_VALUE_FALSE}})

/*** General functions ***/

/**
 * \brief Function that decides the equality between RValues. Bottom line
 * is that two references are deemed equal if they point to the same block.
 * The only exception to this rule is the equality between strings which uses
 * strcmp(). Two direct values are deemed equal if they are bit-for-bit equal.
 * \return true if the two operands are equal according to the scheme
 * described above.
 **/
bool r_value_equal(RValue a, RValue b);

/**
 * \brief Get a uint32_t hash of a RValue.
 **/
uint32_t r_value_hash(RValue v);

#endif /* R_VALUE_H */
